package cc.siyecao.fastdfs.command.storage;

import cc.siyecao.fastdfs.downloader.Downloader;
import cc.siyecao.fastdfs.model.RecvHeaderInfo;
import cc.siyecao.fastdfs.protocol.ProtocolConstants;
import cc.siyecao.fastdfs.util.BytesUtil;
import cc.siyecao.fastdfs.util.ProtocolUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * 文件下载命令
 *
 * @author lyt
 */
public class DownloadCommand extends FdfsStorageCommand<Integer> {

    /**
     * 下载部分文件
     *
     * @param groupName
     * @param remoteFileName
     * @param fileOffset
     * @param downloadBytes
     */
    public DownloadCommand(String groupName, String remoteFileName, long fileOffset, long downloadBytes, Downloader downloader) {
        this.groupName = groupName;
        this.fileName = remoteFileName;
        this.fileOffset = fileOffset;
        this.fileSize = downloadBytes;
        this.downloader = downloader;
    }

    /**
     * 下载文件
     *
     * @param groupName
     * @param remoteFileName
     */
    public DownloadCommand(String groupName, String remoteFileName, Downloader downloader) {
        this.groupName = groupName;
        this.fileName = remoteFileName;
        this.fileOffset = 0;
        this.fileSize = 0;
        this.downloader = downloader;
    }

    @Override
    protected void send(OutputStream out, Charset charset) throws Exception {
        byte[] header;
        byte[] bsOffset;
        byte[] bsDownBytes;
        byte[] groupBytes;
        byte[] fileNameBytes;
        byte[] bs;
        int groupLen;

        bsOffset = BytesUtil.long2buff( fileOffset );
        bsDownBytes = BytesUtil.long2buff( fileSize );
        groupBytes = new byte[ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN];
        bs = groupName.getBytes( charset );
        fileNameBytes = fileName.getBytes( charset );

        Arrays.fill( groupBytes, (byte) 0 );
        if (bs.length <= groupBytes.length) {
            groupLen = bs.length;
        } else {
            groupLen = groupBytes.length;
        }
        System.arraycopy( bs, 0, groupBytes, 0, groupLen );

        header = ProtocolUtil.packHeader( STORAGE_PROTO_CMD_DOWNLOAD_FILE, bsOffset.length + bsDownBytes.length + groupBytes.length + fileNameBytes.length, (byte) 0 );
        byte[] wholePkg = new byte[header.length + bsOffset.length + bsDownBytes.length + groupBytes.length + fileNameBytes.length];
        System.arraycopy( header, 0, wholePkg, 0, header.length );
        System.arraycopy( bsOffset, 0, wholePkg, header.length, bsOffset.length );
        System.arraycopy( bsDownBytes, 0, wholePkg, header.length + bsOffset.length, bsDownBytes.length );
        System.arraycopy( groupBytes, 0, wholePkg, header.length + bsOffset.length + bsDownBytes.length, groupBytes.length );
        System.arraycopy( fileNameBytes, 0, wholePkg, header.length + bsOffset.length + bsDownBytes.length + groupBytes.length, fileNameBytes.length );
        out.write( wholePkg );
    }

    @Override
    protected Integer receive(InputStream in, Charset charset) throws Exception {
        RecvHeaderInfo header = ProtocolUtil.recvHeader( in, STORAGE_PROTO_CMD_RESP, -1 );
        this.errno = header.errno;
        if (header.errno != 0) {
            return Integer.valueOf( header.errno );
        }
        byte[] buff = new byte[2 * 1024];
        long remainBytes = header.bodyLen;
        int bytes, result;

        //System.out.println("expect_body_len=" + header.bodyLen);
        while (remainBytes > 0) {
            if ((bytes = in.read( buff, 0, remainBytes > buff.length ? buff.length : (int) remainBytes )) < 0) {
                throw new IOException( "recv package size " + (header.bodyLen - remainBytes) + " != " + header.bodyLen );
            }
            if ((result = downloader.download( header.bodyLen, buff, bytes )) != 0) {
                this.errno = (byte) result;
                return result;
            }
            remainBytes -= bytes;
            //System.out.println("totalBytes=" + (header.bodyLen - remainBytes));
        }
        return 0;
    }
}
